/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package negocio;

import datos.Foto;
import datos.Obra;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Date;
import java.util.List;
import javax.ejb.Stateless;
import javax.imageio.ImageIO;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

/**
 *
 * @author Ing. Monica Merlo, Ing. Agustin  Fernandez
 */
@Stateless
public class GestorFotosBean implements GestorFotosRemote, GestorFotosLocal {

    static Logger logger = Logger.getLogger(GestorFotosBean.class);

    public static void log4jArchivo (Exception e){
        /**
         * Primero obtenemos la url del archivo de configuración,
         * como están en el mismo paquete que la clase Main lo podemos obtener con el método getResource().
         */
        URL url = GestorFotosBean.class.getResource("/configuracion/log4j.properties");
        /**
         * Despues cargamos el archivo de configuración
         */
        PropertyConfigurator.configure(url);
        logger.error(e);
    }

    @PersistenceContext
    private EntityManager em;

   /***
    * Retorna una lista con todas las instancias de Foto que guarden dependencia con una instancia de
    * Obra con id igual al valor del parametro idObra.
    * @param idObra
    * @return lista con todas las fotos pertenecientes a la obra con ID idObra, y null en caso contrario
    * interfaz local
    */
    public List fotosPorObra(int idObra) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Foto.findByIdObraFotos");
            q.setParameter("idObra", idObra);
            return q.getResultList();

        } catch (Exception e) {
            GestorFotosBean.log4jArchivo(e);
            return null;
        }

    }

    /***
     * Retorna una lista con todas las instancias de Foto que guarden dependencia con una instancia de
     * Obra con id igual al valor del parametro idObra.
     * @param idObra
     * @return lista con todas las fotos pertenecientes a la obra con ID idObra, y null en caso contrario
     * interfaz remota
     */
    public List fotosPorObraRemote(int idObra) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Foto.findByIdObraFotos");
            q.setParameter("idObra", idObra);
            return q.getResultList();

        } catch (Exception e) {
            GestorFotosBean.log4jArchivo(e);
            return null;
        }

    }

    /***
    * Retorna una lista de 0 hasta cantFotos con todas las instancias de Foto que guarden dependencia con una instancia de
    * Obra con id igual al valor del parametro idObra.
    * @param idObra el id de la obra de la cual se desean obtener las fotos
    * @param cantFotos la cnatidad de fotos que se desea listar
    * @return lista con todas las fotos pertenecientes a la obra con ID idObra, y null en caso contrario
    * interfaz local
    */
    public List ultimasNfotosPorObra(int idObra, int cantFotos) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Foto.encontrarNFotosObra");
            q.setParameter("idObra", idObra);
            q.setFirstResult(0);
            q.setMaxResults(cantFotos);
            return q.getResultList();

        } catch (Exception e) {
            GestorFotosBean.log4jArchivo(e);
            return null;
        }

    }

    /***
    * Retorna una lista de 0 hasta cantFotos con todas las instancias de Foto que guarden dependencia con una instancia de
    * Obra con id igual al valor del parametro idObra.
    * @param idObra el id de la obra de la cual se desean obtener las fotos
    * @param cantFotos la cnatidad de fotos que se desea listar
    * @return lista con todas las fotos pertenecientes a la obra con ID idObra, y null en caso contrario
    * interfaz local
    */
    public List ultimasNfotosPorObraRemote(int idObra, int cantFotos) {
        try {
            javax.persistence.Query q = em.createNamedQuery("Foto.encontrarNFotosObra");
            q.setParameter("idObra", idObra);
            q.setFirstResult(0);
            q.setMaxResults(cantFotos);
            return q.getResultList();

        } catch (Exception e) {
            GestorFotosBean.log4jArchivo(e);
            return null;
        }

    }

    /***
     * Almacena una instancia de Foto para la instancia de Obra con id igual al
     * valor del parametro idObra.
     * @param UrlFotos
     * @param fotoSubir
     * @param idObra
     * @return true si la foto ha sido almacenada con éxito en la BD para la obra con ID idObra,
     * url, y fecha. False en caso contrario
     * interfaz local
     */
    public boolean subirFoto(File UrlFotos, File fotoSubir, int idObra) {
        try {
            File f = fotoSubir;
            BufferedImage bi = cargarBufferedImage(f);
            BufferedImage bImgEscaladaG = escalarTamaño(640, 480, bi);
            BufferedImage bImgEscaladaP = escalarTamaño(100, 80, bi);
            String dir = UrlFotos.getAbsolutePath();
//            String dir = System.getProperty("user.dir");
//            System.out.println(dir);
            String separador = System.getProperty("file.separator");
            guardarImagenEnDisco(bImgEscaladaG, dir + separador + f.getName() + ".jpg", "JPEG");
            guardarImagenEnDisco(bImgEscaladaP, dir + separador + f.getName() + "-Small.jpg", "JPEG");
            Foto foto = new Foto();
            Obra obra = em.find(Obra.class, idObra);
            foto.setIdObra(obra);
            foto.setRuta("../images/fotos/" + f.getName() + ".jpg");
            foto.setRutaThumbnail("../images/fotos/" + f.getName() + "-Small.jpg");
            foto.setFecha(new Date(System.currentTimeMillis()));
            persist(foto);
            em.flush();
            return true;
        } catch (Exception ex) {
            GestorFotosBean.log4jArchivo(ex);
            return false;
        }
    }

    /***
     * Almacena una instancia de Foto para la instancia de Obra con id igual al
     * valor del parametro idObra.
     * @param UrlFotos
     * @param fotoSubir
     * @param idObra
     * @return true si la foto ha sido almacenada con éxito en la BD para la obra con ID idObra,
     * url, y fecha. False en caso contrario
     * interfaz remota
     */

    public boolean subirFotoRemote(File UrlFotos, File fotoSubir, int idObra) {
        try {
            File f = fotoSubir;
            BufferedImage bi = cargarBufferedImage(f);
            BufferedImage bImgEscaladaG = escalarTamaño(640, 480, bi);
            BufferedImage bImgEscaladaP = escalarTamaño(100, 80, bi);
            String dir = UrlFotos.getAbsolutePath();
//            String dir = System.getProperty("user.dir");
//            System.out.println(dir);
            String separador = System.getProperty("file.separator");
            guardarImagenEnDisco(bImgEscaladaG, dir + separador + f.getName() + ".jpg", "JPEG");
            guardarImagenEnDisco(bImgEscaladaP, dir + separador + f.getName() + "-Small.jpg", "JPEG");
            Foto foto = new Foto();
            Obra obra = em.find(Obra.class, idObra);
            foto.setIdObra(obra);
            foto.setRuta("../images/fotos/" + f.getName() + ".jpg");
            foto.setRutaThumbnail("../images/fotos/" + f.getName() + "-Small.jpg");
            foto.setFecha(new Date(System.currentTimeMillis()));
            persist(foto);
            em.flush();
            return true;
        } catch (Exception ex) {
            GestorFotosBean.log4jArchivo(ex);
            return false;
        }
    }

    /***
     * Almacena una instancia de Foto, que es subida desde la aplicación J2ME,
     * para la instancia de Obra con id igual al valor del parametro idObra.
     * @param UrlFotos
     * @param fotoSubir
     * @param idObra
     * @param comentarioFoto
     * @return true si la foto ha sido almacenada con éxito en la BD para la obra con ID idObra,
     * url, y fecha. False en caso contrario
     * interfaz local
     */
    public boolean subirFotoDesdeCelular(File UrlFotos, File fotoSubir, int idObra, String comentarioFoto) {
        try {
            File f = fotoSubir;
            BufferedImage bi = cargarBufferedImage(f);
            BufferedImage bImgEscaladaG = escalarTamaño(640, 480, bi);
            BufferedImage bImgEscaladaP = escalarTamaño(100, 80, bi);
            String dir = UrlFotos.getAbsolutePath();
//            String dir = System.getProperty("user.dir");
//            System.out.println(dir);
            String separador = System.getProperty("file.separator");
            guardarImagenEnDisco(bImgEscaladaG, dir + separador + f.getName() + ".jpg", "JPEG");
            guardarImagenEnDisco(bImgEscaladaP, dir + separador + f.getName() + "-Small.jpg", "JPEG");
            Foto foto = new Foto();
            Obra obra = em.find(Obra.class, idObra);
            foto.setIdObra(obra);
            foto.setRuta("../images/fotos/" + f.getName() + ".jpg");
            foto.setRutaThumbnail("../images/fotos/" + f.getName() + "-Small.jpg");
            foto.setFecha(new Date(System.currentTimeMillis()));
            if(comentarioFoto==null)foto.setDescripcion(null);
            else foto.setDescripcion(comentarioFoto.toUpperCase());
            persist(foto);
            em.flush();
            return true;
        } catch (Exception ex) {
            GestorFotosBean.log4jArchivo(ex);
            return false;
        }
    }

    /***
     * Almacena una instancia de Foto, que es subida desde la aplicación J2ME,
     * para la instancia de Obra con id igual al valor del parametro idObra.
     * @param UrlFotos
     * @param fotoSubir
     * @param idObra
     * @param comentarioFoto
     * @return true si la foto ha sido almacenada con éxito en la BD para la obra con ID idObra,
     * url, y fecha. False en caso contrario
     * interfaz local
     */
    public boolean subirFotoDesdeCelularRemote(File UrlFotos, File fotoSubir, int idObra, String comentarioFoto) {
        try {
            File f = fotoSubir;
            BufferedImage bi = cargarBufferedImage(f);
            BufferedImage bImgEscaladaG = escalarTamaño(640, 480, bi);
            BufferedImage bImgEscaladaP = escalarTamaño(100, 80, bi);
            String dir = UrlFotos.getAbsolutePath();
//            String dir = System.getProperty("user.dir");
//            System.out.println(dir);
            String separador = System.getProperty("file.separator");
            guardarImagenEnDisco(bImgEscaladaG, dir + separador + f.getName() + ".jpg", "JPEG");
            guardarImagenEnDisco(bImgEscaladaP, dir + separador + f.getName() + "-Small.jpg", "JPEG");
            Foto foto = new Foto();
            Obra obra = em.find(Obra.class, idObra);
            foto.setIdObra(obra);
            foto.setRuta("../images/fotos/" + f.getName() + ".jpg");
            foto.setRutaThumbnail("../images/fotos/" + f.getName() + "-Small.jpg");
            foto.setFecha(new Date(System.currentTimeMillis()));
            if(comentarioFoto==null)foto.setDescripcion(null);
            else foto.setDescripcion(comentarioFoto.toUpperCase());
            persist(foto);
            em.flush();
            return true;
        } catch (Exception ex) {
            GestorFotosBean.log4jArchivo(ex);
            return false;
        }
    }

    /***
     * Método que permite ver una foto cuya URL fue enviada desde el celular. Existe para no tener que enviar
     * la foto en tamaño completo al celular, si no unicamente la imagen redimensionada a la pantalla del mismo.
     * @param urlFoto File conteniendo la url de la foto
     * @param anchoFoto el ancho de la foto
     * @param altoFoto el alto de la foto
     * @return devuelve un BufferedImage con la foto escalada al ancho y alto solicitados
     */
    public BufferedImage verFotoDesdeCelular(File urlFoto, int anchoFoto, int altoFoto) {
        BufferedImage bi = cargarBufferedImage(urlFoto);
        BufferedImage bImgEscalada = escalarTamaño(anchoFoto, altoFoto, bi);
        return bImgEscalada;
    }

    /***
     * Método que permite ver una foto cuya URL fue enviada desde el celular. Existe para no tener que enviar
     * la foto en tamaño completo al celular, si no unicamente la imagen redimensionada a la pantalla del mismo.
     * @param urlFoto File conteniendo la url de la foto
     * @param anchoFoto el ancho de la foto
     * @param altoFoto el alto de la foto
     * @return devuelve un BufferedImage con la foto escalada al ancho y alto solicitados
     */
    public BufferedImage verFotoDesdeCelularRemote(File urlFoto, int anchoFoto, int altoFoto) {
        BufferedImage bi = cargarBufferedImage(urlFoto);
        BufferedImage bImgEscalada = escalarTamaño(anchoFoto, altoFoto, bi);
        return bImgEscalada;
    }

    /***
     * Elimina una instancia de Foto cuyo id coincida con el parametro idFoto.
     * @param UrlFotos
     * @param idFoto
     * @return true si la foto con ID idFoto es encontrada en la BD y eliminada con éxito
     * y false en caso contrario
     * interfaz local
     */
    public boolean eliminarFoto(File UrlFotos, int idFoto){
        try {
            String dir = UrlFotos.getAbsolutePath();
            String separador = System.getProperty("file.separator");
            Foto fo = em.find(Foto.class, idFoto);
            int posBarra = fo.getRuta().lastIndexOf("/");
            String nombreFoto = fo.getRuta().substring(posBarra + 1);
            File fotoBorrarDeDisco = new File(dir + separador + nombreFoto);
            fotoBorrarDeDisco.delete();
            posBarra = fo.getRutaThumbnail().lastIndexOf("/");
            nombreFoto = fo.getRutaThumbnail().substring(posBarra + 1);
            fotoBorrarDeDisco = new File(dir + separador + nombreFoto);
            fotoBorrarDeDisco.delete();
            em.remove(fo);
            return true;
        } catch (Exception e) {
            GestorFotosBean.log4jArchivo(e);
            return false;
        }
    }

    /***
     * Elimina una instancia de Foto cuyo id coincida con el parametro idFoto.
     * @param UrlFotos
     * @param idFoto
     * @return true si la foto con ID idFoto es encontrada en la BD y eliminada con éxito
     * y false en caso contrario
     * interfaz remota
     */
    public boolean eliminarFotoRemote(File UrlFotos, int idFoto){
        try {
            String dir = UrlFotos.getAbsolutePath();
            String separador = System.getProperty("file.separator");
            Foto fo = em.find(Foto.class, idFoto);
            int posBarra = fo.getRuta().lastIndexOf("/");
            String nombreFoto = fo.getRuta().substring(posBarra + 1);
            File fotoBorrarDeDisco = new File(dir + separador + nombreFoto);
            fotoBorrarDeDisco.delete();
            posBarra = fo.getRutaThumbnail().lastIndexOf("/");
            nombreFoto = fo.getRutaThumbnail().substring(posBarra + 1);
            fotoBorrarDeDisco = new File(dir + separador + nombreFoto);
            fotoBorrarDeDisco.delete();
            em.remove(fo);
            return true;
        } catch (Exception e) {
            GestorFotosBean.log4jArchivo(e);
            return false;
        }
    }

    /***
     * Actualiza la descripcion de una instancia de Foto cuyo id coincida con el
     * valor del parametro idFoto.
     * @param idFoto
     * @param descripcion
     * @return true  si la foto con ID idFoto es encontrada y actualizada con éxito en la BD junto con su descripción
     * y false en contrario
     * interfaz local
     */
    public boolean modificarDescripcionFoto(int idFoto, String descripcion){
        try {
            Foto fo = em.find(Foto.class, idFoto);
            fo.setDescripcion(descripcion.toUpperCase());
            persist(fo);
            em.flush();
            return true;
        } catch (Exception e) {
            GestorFotosBean.log4jArchivo(e);
            return false;
        }
    }

    /***
     * Actualiza la descripcion de una instancia de Foto cuyo id coincida con el
     * valor del parametro idFoto.
     * @param idFoto
     * @param descripcion
     * @return true  si la foto con ID idFoto es encontrada y actualizada con éxito en la BD junto con su descripción
     * y false en contrario
     * interfaz remota
     */
    public boolean modificarDescripcionFotoRemote(int idFoto, String descripcion){
        try {
            Foto fo = em.find(Foto.class, idFoto);
            fo.setDescripcion(descripcion.toUpperCase());
            persist(fo);
            em.flush();
            return true;
        } catch (Exception e) {
            GestorFotosBean.log4jArchivo(e);
            return false;
        }
    }

    /***
     * Redimensiona el tamaño de la foto de la Obra.
     * @param nMaxWidth
     * @param nMaxHeight
     * @param imgSrc
     * @return escala de la foto de la obra
     */
    private BufferedImage escalarTamaño(int nMaxWidth, int nMaxHeight, BufferedImage imgSrc) {
        int nHeight = imgSrc.getHeight();
        int nWidth = imgSrc.getWidth();
        double scaleX = (double) nMaxWidth / (double) nWidth;
        double scaleY = (double) nMaxHeight / (double) nHeight;
        double fScale = Math.min(scaleX, scaleY);
        return escala(fScale, imgSrc);
    }

    /***
     * Retorna la escala de la imagen original de la foto si la escala es igual a 1
     * y escala actualizada si escala es <> 1.
     * @param scale
     * @param srcImg
     * @return escala de la imagen original de la foto si la escala es igual a 1
     * y escala actualizada si escala es <> 1
     */
    private BufferedImage escala(double scale, BufferedImage srcImg) {
        if (scale == 1) {
            return srcImg;
        }
        AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(scale, scale), null);

        return op.filter(srcImg, null);

    }

    /***
     * Retorna la foto de la Obra si se ha podido leer archivo y null en caso contrario.
     * @param file
     * @return foto de la obra si se ha podido leer archivo y null en caso contrario
     */
    private BufferedImage cargarBufferedImage(File file) {
        BufferedImage image = null;
        try {
            image = ImageIO.read(file);
            return image;
        } catch (Exception e) {
            GestorFotosBean.log4jArchivo(e);
            return null;
        }
    }

    /***
     * guarda foto de la obra en disco
     * @param bi
     * @param destino
     * @param formato
     * @throws IOException
     * guarda imagen (foto) de la obra en disco
     */
    private void guardarImagenEnDisco(BufferedImage bi, String destino, String formato) throws IOException {
        ImageIO.write(bi, formato /* formato */, new File(destino) /* destino */);
    }

    /***
     *
     * @param object
     */
    public void persist(Object object) {
        em.persist(object);
    }



    
}
